home *** CD-ROM | disk | FTP | other *** search
/ Aminet 8 / Aminet 8 (1995)(GTI - Schatztruhe)[!][Oct 1995].iso / Aminet / dev / c / mkid.lha / src / mkid.c < prev    next >
C/C++ Source or Header  |  1995-06-29  |  19KB  |  826 lines

  1. static char copyright[] = "@(#)Copyright (c) 1986, Greg McGary";
  2. static char sccsid[] = "@(#)mkid.c    1.4 86/11/06";
  3.  
  4. #define SAS_C
  5.  
  6. /* #define register */
  7.  
  8. #include    "bool.h"
  9. #ifdef UNIX
  10. #include    <sys/types.h>
  11. #include    <sys/stat.h>
  12. #endif
  13. #include    <stdio.h>
  14. #include    "string.h"
  15. #include    <ctype.h>
  16. #include    "id.h"
  17. #include    "bitops.h"
  18. #include    <errno.h>
  19. #include    "extern.h"
  20. #ifdef AMIGA
  21. #include    <time.h>
  22. #include    <dos.h>
  23. #endif
  24. #ifdef SAS_C
  25. #include    <sys/stat.h>
  26. #endif
  27.  
  28. int idnHashCmp();
  29. int idnQsortCmp();
  30. int round2();
  31. struct idname *newIdName();
  32. void extractId();
  33. void fileIdArgs();
  34. void initHashTable();
  35. void oldIdArgs();
  36. void rehash();
  37. void updateID();
  38. void writeID();
  39.  
  40. long    NameCount;        /* Count of names in database */
  41. long    NumberCount;        /* Count of numbers in database */
  42. long    StringCount;        /* Count of strings in database */
  43. long    SoloCount;        /* Count of identifiers that occur only once */
  44.  
  45. long    HashSize;        /* Total Slots in hash table */
  46. long    HashMaxLoad;        /* Maximum loading of hash table */
  47. long    HashFill;        /* Number of keys inserted in table */
  48. long    HashProbes;        /* Total number of probes */
  49. long    HashSearches;        /* Total number of searches */
  50. struct idname    **HashTable;    /* Vector of idname pointers */
  51.  
  52. bool    Verbose = FALSE;
  53.  
  54. int    ArgsCount = 0;        /* Count of args to save */
  55. int    ScanCount = 0;        /* Count of files to scan */
  56. int    PathCount = 0;        /* Count of files covered in database */
  57. int    BitArraySize;        /* Size of bit array slice (per name) */
  58.  
  59.  
  60. char    *MyName;
  61. static void
  62. usage()
  63. {
  64.     fprintf(stderr, "Usage: %s [-f<idfile>] [-s<dir>] [-r<dir>] [(+|-)l[<lang>]] [-v] [(+|-)S<scanarg>] [-a<argfile>] [-] [-u] [files...]\n", MyName);
  65.     exit(1);
  66. }
  67. main(argc, argv)
  68.     int        argc;
  69.     char        **argv;
  70. {
  71.     char        *arg;
  72.     int        op;
  73.     FILE        *argFILE = NULL;
  74.     char        *idFile = IDFILE;
  75.     char        *rcsDir = NULL;
  76.     char        *sccsDir = NULL;
  77.     struct idarg    *idArgs, *idArgHead;
  78.     bool        keepLang = FALSE;
  79.     int        argsFrom = 0;
  80. #define    AF_CMDLINE    0x1    /* file args came on command line */
  81. #define    AF_FILE        0x2    /* file args came from a file (-f<file>) */
  82. #define    AF_IDFILE    0x4    /* file args came from an old ID file (-u) */
  83. #define    AF_QUERY    0x8    /* no file args necessary: usage query */
  84.  
  85. #ifdef AMIGA
  86.     if(expand_args(argc,argv,&argc,&argv))    // AmigaDOS shell does no wildcard expansion  -olsen
  87.         exit(5);
  88. #endif
  89.  
  90.     MyName = basename(GETARG(argc, argv));
  91. #ifdef ERRLINEBUF
  92.     setlinebuf(stderr);
  93. #endif
  94.  
  95.     idArgs = idArgHead = NEW(struct idarg);
  96.  
  97.     /*
  98.         Process some arguments, and snarf-up some
  99.         others for processing later.
  100.     */
  101.     while (argc) {
  102.         arg = GETARG(argc, argv);
  103.         if (*arg != '-' && *arg != '+') {
  104.             argsFrom |= AF_CMDLINE;
  105.             idArgs->ida_arg = arg;
  106.             idArgs->ida_flags = IDA_SCAN|IDA_PATH;
  107.             idArgs->ida_index = postIncr(&PathCount);
  108.             ScanCount++;
  109.             idArgs = (idArgs->ida_next = NEW(struct idarg));
  110.             continue;
  111.         }
  112.         op = *arg++;
  113.         switch (*arg++)
  114.         {
  115.         case 'u':
  116.             argsFrom |= AF_IDFILE;
  117.             oldIdArgs(idFile, &idArgs);
  118.             break;
  119.         case '\0':
  120.             argsFrom |= AF_FILE;
  121.             fileIdArgs(stdin, &idArgs);
  122.             break;
  123.         case 'a':
  124.             if ((argFILE = fopen(arg, "r")) == NULL) {
  125.                 filerr("open", arg);
  126.                 exit(1);
  127.             }
  128.             argsFrom |= AF_FILE;
  129.             fileIdArgs(argFILE, &idArgs);
  130.             fclose(argFILE);    /* added REJ */
  131.             break;
  132.         case 'f':
  133.             idFile = arg;
  134.             break;
  135.         case 'v':
  136.             Verbose = TRUE;
  137.             break;
  138.         case 'S':
  139.             if (strchr(&arg[-2], '?')) {
  140.                 setScanArgs(op, arg);
  141.                 argsFrom |= AF_QUERY;
  142.             }
  143.             /*FALLTHROUGH*/
  144.         case 'l':
  145.         case 's':
  146.         case 'r':
  147.             idArgs->ida_arg = &arg[-2];
  148.             idArgs->ida_index = -1;
  149.             idArgs->ida_flags = IDA_ARG;
  150.             idArgs = (idArgs->ida_next = NEW(struct idarg));
  151.             ArgsCount++;
  152.             break;
  153.         default:
  154.             usage();
  155.         }
  156.     }
  157.  
  158.     if (argsFrom & AF_QUERY)
  159.         exit(0);
  160.     /*
  161.         File args should only come from one place.  Ding the
  162.         user if arguments came from multiple places, or if none
  163.         were supplied at all.
  164.     */
  165.     switch (argsFrom)
  166.     {
  167.     case AF_CMDLINE:
  168.     case AF_FILE:
  169.     case AF_IDFILE:
  170.         if (PathCount > 0)
  171.             break;
  172.         /*FALLTHROUGH*/
  173.     case 0:
  174.         fprintf(stderr, "%s: Use -u, -f<file>, or cmd-line for file args!\n", MyName);
  175.         usage();
  176.     default:
  177.         fprintf(stderr, "%s: Use only one of: -u, -f<file>, or cmd-line for file args!\n", MyName);
  178.         usage();
  179.     }
  180.  
  181.     if (ScanCount == 0)
  182.         exit(0);
  183.  
  184.     BitArraySize = (PathCount + 7) >> 3;
  185.     initHashTable(ScanCount);
  186.  
  187.     if (access(idFile, 06) < 0
  188.     && (errno != ENOENT || access(dirname(idFile), 06) < 0)) {
  189.         filerr("modify", idFile);
  190.         exit(1);
  191.     }
  192.  
  193.     for (idArgs = idArgHead; idArgs->ida_next; idArgs = idArgs->ida_next) {
  194.         char        *(*scanner)();
  195.         FILE        *srcFILE;
  196.         char        *arg, *lang = NULL, *suff;
  197. /* added = NULL - it assumed locals were zeroed! REJ */
  198.  
  199.         arg = idArgs->ida_arg;
  200.         if (idArgs->ida_flags & IDA_ARG) {
  201.             op = *arg++;
  202.             switch (*arg++)
  203.             {
  204.             case 'l':
  205.                 if (*arg == '\0') {
  206.                     keepLang = FALSE;
  207.                     lang = NULL;
  208.                     break;
  209.                 }
  210.                 if (op == '+')
  211.                     keepLang = TRUE;
  212.                 lang = arg;
  213.                 break;
  214.             case 's':
  215.                 sccsDir = arg;
  216.                 break;
  217.             case 'r':
  218.                 rcsDir = arg;
  219.                 break;
  220.             case 'S':
  221.                 setScanArgs(op, strsav(arg));
  222.                 break;
  223.             default:
  224.                 usage();
  225.             }
  226.             continue;
  227.         }
  228.         if (!(idArgs->ida_flags & IDA_SCAN))
  229.             goto skip;
  230.         if (lang == NULL) {
  231.             if ((suff = strrchr(arg, '.')) == NULL)
  232.                 suff = "";
  233.             if ((lang = getLanguage(suff)) == NULL) {
  234.                 fprintf(stderr, "%s: No language assigned to suffix: `%s'\n", MyName, suff);
  235.                 goto skip;
  236.             }
  237.         }
  238.         if ((scanner = getScanner(lang)) == NULL) {
  239.             fprintf(stderr, "%s: No scanner for language: `%s'\n",
  240.                 MyName, lang);
  241.             goto skip;
  242.         }
  243.         if ((srcFILE = openSrcFILE(arg, sccsDir, rcsDir)) == NULL)
  244.             goto skip;
  245.         if (Verbose)
  246.             fprintf(stderr, "%s: %s\n", lang, arg);
  247.         extractId(scanner, srcFILE, idArgs->ida_index);
  248.         fclose(srcFILE);
  249.     skip:
  250.         if (!keepLang)
  251.             lang = NULL;
  252.     }
  253.  
  254.     if (HashFill == 0)
  255.         exit(0);
  256.  
  257.     if (Verbose)
  258.         fprintf(stderr, "Compressing Hash Table...\n");
  259.     hashCompress(HashTable, HashSize);
  260.     if (Verbose)
  261.         fprintf(stderr, "Sorting Hash Table...\n");
  262.     qsort(HashTable, HashFill, sizeof(struct idname *), idnQsortCmp);
  263.  
  264.     if (argsFrom == AF_IDFILE) {
  265.         if (Verbose)
  266.             fprintf(stderr, "Merging Tables...\n");
  267.         updateID(idFile, idArgHead);
  268.     }
  269.  
  270.     if (Verbose)
  271.         fprintf(stderr, "Writing `%s'...\n", idFile);
  272.     writeID(idFile, idArgHead);
  273.  
  274.     if (Verbose) {
  275.         float loadFactor = (float)HashFill / (float)HashSize;
  276.         float aveProbes = (float)HashProbes / (float)HashSearches;
  277.         float aveOccur = (float)HashSearches / (float)HashFill;
  278.         fprintf(stderr, "Names: %ld, ", NameCount);
  279.         fprintf(stderr, "Numbers: %ld, ", NumberCount);
  280.         fprintf(stderr, "Strings: %ld, ", StringCount);
  281.         fprintf(stderr, "Solo: %ld, ", SoloCount);
  282.         fprintf(stderr, "Total: %ld\n", HashFill);
  283.         fprintf(stderr, "Occurances: %.2f, ", aveOccur);
  284.         fprintf(stderr, "Load: %.2f, ", loadFactor);
  285.         fprintf(stderr, "Probes: %.2f\n", aveProbes);
  286.     }
  287.     exit(0);
  288. }
  289.  
  290. void
  291. extractId(getId, srcFILE, index)
  292.     register char    *(*getId)();
  293.     register FILE    *srcFILE;
  294.     int        index;
  295. {
  296.     register struct idname    **slot;
  297.     register char    *key;
  298.     int        flags;
  299.  
  300.     while ((key = (*getId)(srcFILE, &flags)) != NULL) {
  301.         slot = (struct idname **)hashSearch(key, HashTable, HashSize, sizeof(struct idname *), h1str, h2str, idnHashCmp, &HashProbes);
  302.         HashSearches++;
  303.         if (*slot != NULL) {
  304.             (*slot)->idn_flags |= flags;
  305.             BITSET((*slot)->idn_bitv, index);
  306.             continue;
  307.         }
  308.         *slot = newIdName(key);
  309.         (*slot)->idn_flags = IDN_SOLO|flags;
  310.         BITSET((*slot)->idn_bitv, index);
  311.         if (HashFill++ >= HashMaxLoad)
  312.             rehash();
  313.     }
  314. }
  315.  
  316. void
  317. writeID(idFile, idArgs)
  318.     char        *idFile;
  319.     struct idarg    *idArgs;
  320. {
  321.     register struct idname    **idnp;
  322.     register struct idname    *idn;
  323.     register int    i;
  324.     char        *vecBuf;
  325.     FILE        *idFILE;
  326.     int        count;
  327.     int        lasti;
  328.     long        before, after;
  329.     int        length, longest;
  330.     struct idhead    idh;
  331.  
  332. /* note: for -u to work on non-unix, updateID MUST close idFILE so open */
  333. /* can succeed REJ                             */
  334.     if ((idFILE = fopen(idFile, "w+")) == NULL) {
  335.         filerr("create", idFile);
  336.         exit(1);
  337.     }
  338.     fseek(idFILE, (long)sizeof(struct idhead), 0);
  339.  
  340.     /* write out the list of pathnames */
  341.     idh.idh_argo = ftell(idFILE);
  342.     for (i = lasti = 0; idArgs->ida_next; idArgs = idArgs->ida_next) {
  343.         if (idArgs->ida_index > 0)
  344.             while (++lasti < idArgs->ida_index)
  345.                 i++, putc('\0', idFILE);
  346.         fputs(idArgs->ida_arg, idFILE);
  347.         i++, putc('\0', idFILE);
  348.     }
  349.     idh.idh_argc = i;
  350.     idh.idh_pthc = PathCount;
  351.  
  352.     /* write out the list of identifiers */
  353.     i = 1;
  354.     if (idh.idh_pthc >= 0x000000ff)
  355.         i++;
  356.     if (idh.idh_pthc >= 0x0000ffff)
  357.         i++;
  358.     if (idh.idh_pthc >= 0x00ffffff)
  359.         i++;
  360.     idh.idh_vecc = i;
  361.  
  362.     vecBuf = malloc((idh.idh_pthc + 1) * idh.idh_vecc);
  363.  
  364.     putc('\377', idFILE);
  365.     before = idh.idh_namo = ftell(idFILE);
  366.     longest = 0;
  367.     for (idnp = HashTable, i = 0; i < HashFill; i++, idnp++) {
  368.         idn = *idnp;
  369.         if (idn->idn_name[0] == '\0') {
  370.             HashFill--; i--;
  371.             continue;
  372.         }
  373.         if (idn->idn_flags & IDN_SOLO)
  374.             SoloCount++;
  375.         if (idn->idn_flags & IDN_NUMBER)
  376.             NumberCount++;
  377.         if (idn->idn_flags & IDN_NAME)
  378.             NameCount++;
  379.         if (idn->idn_flags & IDN_STRING)
  380.             StringCount++;
  381.  
  382.         putc((*idnp)->idn_flags, idFILE);
  383.         fputs(idn->idn_name, idFILE);
  384.         putc('\0', idFILE);
  385.  
  386.         count = bitsToVec(vecBuf, (*idnp)->idn_bitv, idh.idh_pthc, idh.idh_vecc);
  387.         fwrite(vecBuf, idh.idh_vecc, count, idFILE);
  388.         putc('\377', idFILE);
  389.         after = ftell(idFILE);
  390.  
  391.         if ((length = (after - before)) > longest)
  392.             longest = length;
  393.         before = after;
  394.     }
  395.     idh.idh_namc = i;
  396.     putc('\377', idFILE);
  397.     idh.idh_endo = ftell(idFILE);
  398.     idh.idh_bsiz = longest;
  399.  
  400.     /* write out the header */
  401.     strncpy(idh.idh_magic, IDH_MAGIC, sizeof(idh.idh_magic));
  402.     idh.idh_vers = IDH_VERS;
  403.     fseek(idFILE, 0L, 0);
  404.     fwrite((char *) &idh, sizeof(struct idhead), 1, idFILE);
  405.  
  406.     fclose(idFILE);
  407. }
  408.  
  409. /*
  410.     Build an idarg vector from pathnames contained in an existing
  411.     id file.  Only include pathnames for files whose modification
  412.     time is later than that of the id file itself.
  413. */
  414. void
  415. oldIdArgs(idFile, idArgsP)
  416.     char        *idFile;
  417.     struct idarg    **idArgsP;
  418. {
  419. #ifdef UNIX
  420.     struct stat    statBuf;
  421. #endif
  422. #ifdef SAS_C
  423.     struct stat    statBuf;
  424. #endif
  425.     struct idhead    idh;
  426.     FILE        *idFILE;
  427.     register int    i;
  428.     register char    *strings;
  429.     time_t        idModTime;
  430. /*
  431. #ifdef AMIGA
  432.     time_t        tmptime;
  433. #endif
  434. */
  435.     if ((idFILE = fopen(idFile, "r")) == NULL) {
  436.         filerr("open", idFile);
  437.         usage();
  438.     }
  439.     /*
  440.     *  Open the id file, get its mod-time, and read its header.
  441.     */
  442. #ifdef UNIX
  443.     if (fstat(fileno(idFILE), &statBuf) < 0) {
  444.         filerr("stat", idFile);
  445.         usage();
  446.     }
  447.     idModTime = statBuf.st_mtime;
  448. #endif
  449. /*
  450. #ifdef AMIGA
  451.     if ((idModTime = getft(idFile)) == -1) {
  452.         filerr("getft(stat)",idFile);
  453.         usage();
  454.     }
  455. #endif
  456. */
  457. #ifdef SAS_C
  458.     if (stat(idFile, &statBuf) < 0) {
  459.         filerr("stat", idFile);
  460.         usage();
  461.     }
  462.     idModTime = statBuf.st_mtime;
  463. #endif
  464.     fread((char *) &idh, sizeof(struct idhead), 1, idFILE);
  465.     if (!strnequ(idh.idh_magic, IDH_MAGIC, sizeof(idh.idh_magic))) {
  466.         fprintf(stderr, "%s: Not an id file: `%s'\n", MyName, idFile);
  467.         exit(1);
  468.     }
  469.     if (idh.idh_vers != IDH_VERS) {
  470.         fprintf(stderr, "%s: ID version mismatch (%ld,%ld)\n", MyName, idh.idh_vers, IDH_VERS);
  471.         exit(1);
  472.     }
  473.  
  474.     /*
  475.     *  Read in the id pathnames, compare their mod-times with
  476.     *  the id file, and incorporate the pathnames of recently modified
  477.     *  files in the idarg vector.  Also, construct a mask of
  478.     *  bit array positions we want to turn off when we build the
  479.     *  initial hash-table.
  480.     */
  481.     fseek(idFILE, idh.idh_argo, 0);
  482.     strings = malloc(i = idh.idh_namo - idh.idh_argo);
  483.     fread(strings, i, 1, idFILE);
  484.     ScanCount = 0;
  485.     for (i = 0; i < idh.idh_argc; i++) {
  486.         (*idArgsP)->ida_arg = strings;
  487.         if (*strings == '+' || *strings == '-') {
  488.             (*idArgsP)->ida_flags = IDA_ARG;
  489.             (*idArgsP)->ida_index = -1;
  490.         } else {
  491.             (*idArgsP)->ida_flags = IDA_PATH;
  492.             (*idArgsP)->ida_index = postIncr(&PathCount);
  493. #ifdef SAS_C
  494.             if (stat(strings, &statBuf) < 0)
  495.                 filerr("stat", strings);
  496.             else if (statBuf.st_mtime >= idModTime) {
  497. #endif
  498. /*
  499. #ifdef UNIX
  500.             if (stat(strings, &statBuf) < 0) {
  501.                 filerr("stat", strings);
  502.             } else if (statBuf.st_mtime >= idModTime) {
  503. #endif
  504. */
  505. /*
  506. #ifdef AMIGA
  507.             if ((tmptime = getft(strings)) == -1)
  508.                 filerr("getft(stat)",strings);
  509.             else if (tmptime >= idModTime) {
  510. #endif
  511. */
  512.                 (*idArgsP)->ida_flags |= IDA_SCAN;
  513.                 ScanCount++;
  514.             }
  515.         }
  516.         (*idArgsP) = ((*idArgsP)->ida_next = NEW(struct idarg));
  517.         while (*strings++)
  518.             ;
  519.     }
  520.     fclose(idFILE);
  521.  
  522.     if (ScanCount == 0) {
  523.         exit(0);
  524.     }
  525. }
  526.  
  527. void
  528. updateID(idFile, idArgs)
  529.     char        *idFile;
  530.     struct idarg    *idArgs;
  531. {
  532.     struct idname    *idn;
  533.     struct idhead    idh;
  534.     register char    *bitArray;
  535.     char        *entry0;
  536.     register int    i;
  537.     FILE        *idFILE;
  538.     int        cmp, count, size;
  539.     char        *bitsOff;
  540.     struct idname    **newTable, **mergeTable;
  541.     struct idname    **t1, **t2, **tm;
  542.  
  543.     if ((idFILE = fopen(idFile, "r")) == NULL)
  544.         filerr("open", idFile);
  545.     fread((char *) &idh, sizeof(struct idhead), 1, idFILE);
  546.  
  547.     entry0 = malloc(idh.idh_bsiz);
  548.  
  549.     bitsOff = malloc(BitArraySize);
  550.     bzero(bitsOff, BitArraySize);
  551.     for (i = 0; idArgs->ida_next; idArgs = idArgs->ida_next)
  552.         if (idArgs->ida_flags & IDA_SCAN)
  553.             BITSET(bitsOff, idArgs->ida_index);
  554.  
  555.     bitArray = malloc(BitArraySize);
  556.     bzero(bitArray, BitArraySize);
  557.     t2 = newTable = (struct idname **)malloc((idh.idh_namc + 1) * sizeof(struct idname *));
  558. #ifdef UNIX
  559.     fseek(idFILE, idh.idh_namo, 0);
  560. #endif
  561. #ifdef AMIGA    /* paranoia */
  562.     if (fseek(idFILE, idh.idh_namo, 0) == -1)
  563.         filerr("fseek",idFILE);
  564. #endif
  565.     count = 0;
  566.     for (i = 0; i < idh.idh_namc; i++) {
  567.         size = 1 + fgets0(entry0, idh.idh_bsiz, idFILE);
  568.         getsFF(&entry0[size], idFILE);
  569.         vecToBits(bitArray, &entry0[size], idh.idh_vecc);
  570.         bitsclr(bitArray, bitsOff, BitArraySize);
  571.         if (!bitsany(bitArray, BitArraySize))
  572.             continue;
  573.         *t2 = newIdName(ID_STRING(entry0));
  574.         bitsset((*t2)->idn_bitv, bitArray, BitArraySize);
  575.         (*t2)->idn_flags = ID_FLAGS(entry0);
  576.         bzero(bitArray, BitArraySize);
  577.         t2++; count++;
  578.     }
  579.     *t2 = NULL;
  580. #ifdef AMIGA    /* and probably others! */
  581.     if (fclose(idFILE) == -1)
  582.         filerr("close",idFILE);
  583. #endif
  584.  
  585.     t1 = HashTable;
  586.     t2 = newTable;
  587.     tm = mergeTable = (struct idname **)calloc(HashFill + count + 1, sizeof(struct idname *));
  588.     while (*t1 && *t2) {
  589.         cmp = strcmp((*t1)->idn_name, (*t2)->idn_name);
  590.         if (cmp < 0)
  591.             *tm++ = *t1++;
  592.         else if (cmp > 0)
  593.             *tm++ = *t2++;
  594.         else {
  595.             (*t1)->idn_flags |= (*t2)->idn_flags;
  596.             (*t1)->idn_flags &= ~IDN_SOLO;
  597.             bitsset((*t1)->idn_bitv, (*t2)->idn_bitv, BitArraySize);
  598.             *tm++ = *t1;
  599.             t1++, t2++;
  600.         }
  601.     }
  602.     while (*t1)
  603.         *tm++ = *t1++;
  604.     while (*t2)
  605.         *tm++ = *t2++;
  606.     *tm = NULL;
  607.     HashTable = mergeTable;
  608.     HashFill = tm - mergeTable;
  609. }
  610.  
  611. /*
  612.     Cons up a list of idArgs as supplied in a file.
  613. */
  614. void
  615. fileIdArgs(argFILE, idArgsP)
  616.     FILE        *argFILE;
  617.     struct idarg    **idArgsP;
  618. {
  619. /*    int        fileCount; not really used REJ */
  620.     char        buf[BUFSIZ];
  621.     char        *arg;
  622.     int        len;    /* avoid macro trouble  -olsen */
  623.  
  624. /*     fileCount = 0; see? REJ */
  625.     while (fgets(buf, sizeof(buf), argFILE)) {
  626.         len = strlen(buf);
  627.         if (len <= 1)
  628.             continue;    /* don't save null args REJ */
  629.         (*idArgsP)->ida_arg = arg = strnsav(buf, len-1);
  630.         if (*arg == '+' || *arg == '-') {
  631.             (*idArgsP)->ida_flags = IDA_ARG;
  632.             (*idArgsP)->ida_index = -1;
  633.         } else {
  634.             (*idArgsP)->ida_flags = IDA_SCAN|IDA_PATH;
  635.             (*idArgsP)->ida_index = postIncr(&PathCount);
  636.             ScanCount++;
  637.         }
  638.         (*idArgsP) = ((*idArgsP)->ida_next = NEW(struct idarg));
  639.     }
  640. }
  641.  
  642. void
  643. initHashTable(pathCount)
  644.     int        pathCount;
  645. {
  646.     if ((HashSize = round2((pathCount << 6) + 511)) > 0x8000)
  647.         HashSize = 0x8000;
  648.     HashMaxLoad = HashSize - (HashSize >> 4);    /* about 94% */
  649.     HashTable = (struct idname **)calloc(HashSize, sizeof(struct idname *));
  650. }
  651.  
  652. /*
  653.     Double the size of the hash table in the
  654.     event of overflow...
  655. */
  656. void
  657. rehash()
  658. {
  659.     long        oldHashSize = HashSize;
  660.     struct idname    **oldHashTable = HashTable;
  661.     register struct idname    **htp;
  662.     register struct idname    **slot;
  663.  
  664.     HashSize *= 2;
  665.     if (Verbose)
  666.         fprintf(stderr, "Rehashing... (doubling size to %ld)\n", HashSize);
  667.     HashMaxLoad = HashSize - (HashSize >> 4);
  668.     HashTable = (struct idname **)calloc(HashSize, sizeof(struct idname *));
  669.  
  670.     HashFill = 0;
  671.     for (htp = oldHashTable; htp < &oldHashTable[oldHashSize]; htp++) {
  672.         if (*htp == NULL)
  673.             continue;
  674.         slot = (struct idname **)hashSearch((*htp)->idn_name, (char *)HashTable, HashSize, sizeof(struct idname *), h1str, h2str, idnHashCmp, &HashProbes);
  675.         if (*slot) {
  676.             fprintf(stderr, "%s: Duplicate hash entry!\n");
  677.             exit(1);
  678.         }
  679.         *slot = *htp;
  680.         HashSearches++;
  681.         HashFill++;
  682.     }
  683.     free(oldHashTable);
  684. }
  685.  
  686. /*
  687.     Round a given number up to the nearest power of 2.
  688. */
  689. int
  690. round2(rough)
  691.     int        rough;
  692. {
  693.     int        round;
  694.  
  695.     round = 1;
  696.     while (rough) {
  697.         round <<= 1;
  698.         rough >>= 1;
  699.     }
  700.     return round;
  701. }
  702.  
  703. /*
  704.     `compar' function for hashSearch()
  705. */
  706. int
  707. idnHashCmp(key, idn)
  708.     char        *key;
  709.     struct idname    **idn;
  710. {
  711.     int        collate;
  712.  
  713.     if (*idn == NULL)
  714.         return 0;
  715.  
  716.     if ((collate = strcmp(key, (*idn)->idn_name)) == 0)
  717.         (*idn)->idn_flags &= ~IDN_SOLO;    /* we found another occurance */
  718.  
  719.     return collate;
  720. }
  721.  
  722. /*
  723.     `compar' function for qsort().
  724. */
  725. int
  726. idnQsortCmp(idn1, idn2)
  727.     struct idname    **idn1;
  728.     struct idname    **idn2;
  729. {
  730.     if (*idn1 == *idn2)
  731.         return 0;
  732.     if (*idn1 == NULL)
  733.         return 1;
  734.     if (*idn2 == NULL)
  735.         return -1;
  736.  
  737.     return strcmp((*idn1)->idn_name, (*idn2)->idn_name);
  738. }
  739.  
  740. /*
  741.     Allocate a new idname struct and fill in the name field.
  742.     We allocate memory in large chunks to avoid frequent
  743.     calls to malloc() which is a major pig.
  744. */
  745. struct idname *
  746. newIdName(name)
  747.     char        *name;
  748. {
  749.     register struct idname    *idn;
  750.     register char    *allocp;
  751.     register int    allocsiz;
  752.     static char    *allocBuf = NULL;
  753.     static char    *allocEnd = NULL;
  754. #define    ALLOCSIZ    (8*1024)
  755.  
  756.     allocsiz = sizeof(struct idname) + strlen(name) + 1 + BitArraySize;
  757.     allocsiz += (sizeof(long) - 1);
  758.     allocsiz &= ~(sizeof(long) - 1);
  759.  
  760.     allocp = allocBuf;
  761.     allocBuf += allocsiz;
  762.     if (allocBuf > allocEnd) {
  763.         allocBuf = malloc(ALLOCSIZ);
  764.         allocEnd = &allocBuf[ALLOCSIZ];
  765.         allocp = allocBuf;
  766.         allocBuf += allocsiz;
  767.     }
  768.  
  769.     idn = (struct idname *)allocp;
  770.     allocp += sizeof(struct idname);
  771.     idn->idn_bitv = allocp;
  772.     for (allocsiz = BitArraySize; allocsiz--; allocp++)
  773.         *allocp = '\0';
  774.     idn->idn_name = strcpy(allocp, name);
  775.  
  776.     return idn;
  777. }
  778.  
  779. int
  780. postIncr(ip)
  781.     int        *ip;
  782. {
  783.     register int    i;
  784.     int        save;
  785.  
  786.     save = *ip;
  787.     i = save + 1;
  788.     if ((i & 0x00ff) == 0x00ff)
  789.         i++;
  790.     if ((i & 0xff00) == 0xff00)    /* This isn't bloody likely */
  791.         i += 0x100;
  792.     *ip = i;
  793.  
  794.     return save;
  795. }
  796.  
  797. /*
  798.     Move all non-NULL table entries to the front of the table.
  799.     return the number of non-NULL elements in the table.
  800. */
  801. int
  802. hashCompress(table, size)
  803.     char        **table;
  804.     int        size;
  805. {
  806.     register char    **front;
  807.     register char    **back;
  808.  
  809.     front = &table[-1];
  810.     back = &table[size];
  811.  
  812.     for (;;) {
  813.         while (*--back == NULL)
  814.             ;
  815.         if (back < front)
  816.             break;
  817.         while (*++front != NULL)
  818.             ;
  819.         if (back < front)
  820.             break;
  821.         *front = *back;
  822.     }
  823.  
  824.     return (back - table + 1);
  825. }
  826.